﻿#pragma once
#include "as_mysql_config.h"
#include "co_promisc.h"
#include <memory>
#include <queue>
#include <future>


#define LOG_THREAD(str) std::cout << "[" << std::this_thread::get_id() << "]" << __FUNCTION__ << ":" << str << "\n";

struct MYSQL_RES;
struct MYSQL;
namespace as
{
	namespace db
	{
		class MysqlResult;
		class MysqlScopeInit
		{
		public:
			MysqlScopeInit(int argc = 0, char** argv = nullptr, char** group = nullptr);
			~MysqlScopeInit();
		};

		class MysqlConnection;

		//承诺体
		struct QueryPromise
		{
			struct promise_type
			{
				QueryPromise get_return_object()
				{
					return QueryPromise{ .handle = std::coroutine_handle<promise_type>::from_promise(*this) };
				}

				//协程启动时,是否挂起
				std::suspend_always initial_suspend() { return {}; }

				//协程完成后,是否挂起
				std::suspend_always final_suspend() noexcept
				{
					LOG_THREAD("end promise");
					return {};
				}
				void return_void()
				{
				}

				//在协程中发生未捕获的异常时被调用。通常会将异常存储起来，稍后可以在协程的返回对象中访问。
				void unhandled_exception() {
					std::exit(1);
				}
			};

			std::coroutine_handle<promise_type> handle;

			~QueryPromise()
			{
				LOG_THREAD("QueryPromise delete");
			}
		};


		//等待体
		struct QueryAwait
		{
			using promise_type = QueryPromise::promise_type;
			using handle_t = std::coroutine_handle<promise_type>;

			QueryAwait(MysqlConnection* conn, const std::string_view& cmd) :conn_(conn), cmd_(cmd) {};
			bool await_ready() noexcept;
			void await_suspend(std::coroutine_handle<promise_type> handle) noexcept;
			std::shared_ptr<MysqlResult> await_resume() noexcept;
			std::shared_ptr<MysqlResult> res_ = nullptr;
			MysqlConnection* conn_ = nullptr;
			std::string_view cmd_ = nullptr;
		};


		class MysqlConnection
		{
		public:
			enum Err
			{
				NONE = 0,
				CONNECT_ERROR = 1,
				QUERY_ERROR = 2,
			};
			MysqlConnection(MYSQL* conn, const MysqlConnConfig& conf);
			MysqlConnection(const MysqlConnConfig& conf);
			~MysqlConnection();

			std::shared_ptr<MysqlResult> Exce(const std::string_view& cmd);
			QueryAwait co_exce(const std::string_view& cmd);

			bool IsAutoReconnect()const;
			bool IsConnect()const;
			bool IsStop()const { return is_stop_; }
			void Stop() { is_stop_ = true; }
			Err GetError()const;
			const char* GetErrorLog() const;

			void ReleaseResult(MysqlResult* result);
		protected:
			bool Reconnect();
			void CloseConn(Err log, const std::string_view& errlog);
			void SetError(Err log, const std::string_view& errlog);

			MysqlResult* AllocResult(MYSQL_RES* res);
		private:
			std::mutex lock_;
			Err err_ = Err::NONE;
			std::string err_str_;
			MYSQL* conn_;
			MysqlConnConfig conf_;
			std::atomic_bool is_stop_ = false;
		};
	}
}
